/**
 * Created by wm123 on 2017/7/13.
 */
const extend = require('extend');

const { Game, Dispatcher } = require('board-game');
const { game } = require('./config');

class Gift {
    constructor(type, location) {
        this.type = type;
        this.location = location;
        this.tick = game.wait.giftFrame;
        this.got = false;
    }
    static randomType() {
        let types = [];
        for (let gift of Object.keys(game.probability)) {
            types.push(...new Array(game.probability[gift]).fill(gift));
        }
        return game.gift[types[Math.floor(Math.random() * types.length)]];
    }
    get(tank) {
        this.got = tank;
        this.tick = game.wait.getGiftFrame;
    }
    get data() {
        return {
            type: this.type,
            tick: this.tick,
            got: !!this.got,
            location: {
                x: this.location.x,
                y: this.location.y
            }
        }
    }
}

class Bullet {
    constructor(tank, direction, location, speed, strong) {
        this.tank = tank;
        this.direction = direction;
        this.location = location;
        this.speed = speed;
        this.strong = strong;
        this.boom = 0;
        this.end = 'none';
        this.tick = 0;
    }
    move() {
        let offset = game.wait.bullet(this.speed);
        let locations = [];
        for (let i = 0; i < offset; i += game.hint.bullet) {
            let d = Math.min(offset - i, game.hint.bullet);
            this.location.x += this.direction === game.direction.right ? d : this.direction === game.direction.left ? -d : 0;
            this.location.y += this.direction === game.direction.top ? -d : this.direction === game.direction.bottom ? d : 0;
            locations.push({ x: this.location.x, y: this.location.y });
        }
        return locations;
    }
    hint(bullet) {
        if (Math.abs(this.location.x - bullet.location.x) < game.hint.bullet + game.hint.bullet && Math.abs(this.location.y - bullet.location.y) < game.hint.bullet + game.hint.bullet) {
            this.boom = game.wait.boom;
            return true;
        } else {
            return false;
        }
    }
    get data() {
        return {
            direction: this.direction,
            location: {
                x: this.location.x,
                y: this.location.y
            },
            boom: this.boom,
            end: this.end,
            tick: this.tick,
        };
    }
}

//waiting: 等待开始
//born: 出生
class Tank {
    constructor(battle, role, life, gifts = 0) {
        this.battle = battle;
        this.role = role;
        this.life = life;
        this.safe = 0;
        this.ship = false;
        this.speed = this.isEnemy ? game.enemy[this.role].speed || 1 : 2;
        this.fire = this.isEnemy ? game.enemy[this.role].fire || 1 : 1;
        this.gifts = this.isEnemy ? new Array(gifts).fill(0).map(() => Gift.randomType()) : [];
        this.location = { x: -1, y: -1 };
        this.direction = game.direction.none;
        this.bullets = [];
        this.pushes = [];
        this.ice = 0;
        this.enemy = false;
        this.score = {
            value: 0,
            current: 0,
            first: false,
            enemies: [ 0, 0, 0, 0 ],
            gifts: 0
        };
        this.current = {
            status: 'waiting',
            tick: 0
        };
    }
    get tick() {
        return this.current.tick;
    }
    set status(value) {
        if (this.current.status === value) {
            this.current.tick ++;
        } else {
            this.current.status = value;
            this.current.tick = 0;
            if (value === 'waiting') {
                this.bullets = [];
            } else if (value === 'immobilize') {
                this.end();
            }
        }
    }
    get status() {
        return this.current.status;
    }
    get percent() {
        return this.status === 'moving' ? Math.min(100, Math.round(this.tick / (game.wait.move(this.speed) + 1) * 100)) : 0;
    }
    get border() {
        switch(this.direction) {
            case game.direction.top: return { x: this.location.x, y: this.location.y - 1 };
            case game.direction.right: return { x: this.location.x + 1, y: this.location.y };
            case game.direction.bottom: return { x: this.location.x, y: this.location.y + 1 };
            case game.direction.left: return { x: this.location.x - 1, y: this.location.y };
            default: return this.location;
        }
    }
    get push() {
        return this.pushes.length ? this.pushes[0] : game.direction.none;
    }
    relive(player) {
        if (this.role.player.id !== player) {
            if (this.life >= 3 && this.battle.status === 'fighting') {
                let reliveTank = this.battle.tanks.find(tank => tank.role.player.id === player);
                if (reliveTank && reliveTank.life === 0) {
                    this.life--;
                    reliveTank.life++;
                    reliveTank.status = 'born';
                    let index = this.battle.tanks.indexOf(reliveTank);
                    let { x, y, d } = game.locations[this.battle.board.index][index % game.locations[this.battle.board.index].length];
                    reliveTank.location = { x, y };
                    reliveTank.direction = d;
                }
            }
        }
    }
    start(direction) {
        // if (this.status !== 'moving' && this.status !== 'original' && this.status !== 'stop' && this.status !== 'born') return;
        if (this.status === 'immobilize') return;
        if (this.pushes.includes(direction)) return;
        this.pushes.push(direction);
        if (this.status !== 'moving') {
            this.direction = direction;
        }
    }
    end(direction) {
        if (direction === -1) {
            this.pushes.splice(0);
        } else {
            let index = this.pushes.indexOf(direction);
            if (index >= 0) {
                this.pushes.splice(this.pushes.indexOf(direction), 1);
            }
        }
    }
    move(move = true) {
        if (move) {
            switch (this.direction) {
                case game.direction.top: this.location.y--; break;
                case game.direction.right: this.location.x++; break;
                case game.direction.bottom: this.location.y++; break;
                case game.direction.left: this.location.x--; break;
            }
        }
        if (this.push !== game.direction.none) {
            this.direction = this.push;
            return true;
        } else {
            return false;
        }
    }
    shot() {
        if (this.status !== 'moving' && this.status !== 'original' && this.status !== 'stop' && this.status !== 'immobilize') return;
        let { speed, strong, count } = game.bullet[this.fire - 1];
        if (this.bullets.filter(bullet => bullet.tick < game.wait.bulletSpaceFrame).length === 0 && this.bullets.filter(bullet => bullet.boom <= game.wait.bulletBoomFrame).length < count) {
            let { x, y } = this.border;
            this.bullets.push(new Bullet(this, this.direction, { x: x * 100 + (this.direction === game.direction.right ? this.percent : this.direction === game.direction.left ? -this.percent : 0), y: y * 100 + (this.direction === game.direction.top ? -this.percent : this.direction === game.direction.bottom ? this.percent : 0) }, speed, strong));
        }
    }
    hint(element, next = false) {
        if (element instanceof Bullet) {
            let bullet = element;
            if (Math.abs(this.location.x * 100 + (this.direction === game.direction.right ? this.percent : this.direction === game.direction.left ? -this.percent : 0) - bullet.location.x) <= game.hint.tank + game.hint.bullet && Math.abs(this.location.y * 100 + (this.direction === game.direction.top ? -this.percent : this.direction === game.direction.bottom ? this.percent : 0) - bullet.location.y) <= game.hint.tank + game.hint.bullet) {
                if (this.isEnemy) {
                    if (this.gifts.length) {
                        this.battle.pushGift(this.gifts.shift());
                    } else {
                        this.life--;
                        if (this.life === 0) {
                            this.status = 'death';
                            bullet.tank.score.enemies[this.role]++;
                        }
                    }
                } else {
                    if (bullet.tank.isEnemy) {
                        if (!this.safe) {
                            if (this.ship) {
                                this.ship = false;
                            } else if (this.fire > 1) {
                                this.fire = 1;
                            } else {
                                this.life--;
                                this.status = 'death';
                                this.enemy = false;
                            }
                        }
                    } else if (this.battle.board.settings.teamDamage) {
                        if (!this.safe) {
                            this.status = 'immobilize';
                            this.current.tick = 0;
                            this.enemy = bullet.tank;
                        }
                    } else {
                        return false;
                    }
                }
                return true;
            } else {
                return false;
            }
        } else if (element instanceof Tank) {
            let tank = element;
            let x = tank.status !== 'waiting' ? tank.location.x + (tank.direction === game.direction.right ? 1 : tank.direction === game.direction.left ? -1 : 0) : tank.location.x;
            let y = tank.status !== 'waiting' ? tank.location.y + (tank.direction === game.direction.top ? -1 : tank.direction === game.direction.bottom ? 1 : 0) : tank.location.y;
            if (Math.abs(this.location.x - x) < 2 && Math.abs(this.location.y - y) < 2) {
                return true;
            } else if (this.status === 'moving' && (this.percent > 0 || next)
                && Math.abs(this.location.x + (this.direction === game.direction.right ? 1 : this.direction === game.direction.left ? -1 : 0) - x) < 2
                && Math.abs(this.location.y + (this.direction === game.direction.top ? -1 : this.direction === game.direction.bottom ? 1 : 0) - y) < 2) {
                return true;
            } else {
                return false;
            }
        } else if (element instanceof Gift) {
            let gift = element;
            let { x, y } = gift.location;
            if (gift.got) {
                return false;
            } else if (Math.abs(this.location.x - x) < 2 && Math.abs(this.location.y - y) < 2) {
                this.score.gifts++;
                return true;
            } else if (this.status === 'moving' && (this.percent > 0 || next)
                && Math.abs(this.location.x + (this.direction === game.direction.right ? 1 : this.direction === game.direction.left ? -1 : 0) - x) < 2
                && Math.abs(this.location.y + (this.direction === game.direction.top ? -1 : this.direction === game.direction.bottom ? 1 : 0) - y) < 2) {
                this.score.gifts++;
                return true;
            } else {
                return false;
            }
        } else {
            let { x, y } = element;
            if (this.location.x - x >= 0 && this.location.x - x <= 1 && this.location.y - y >= 0 && this.location.y - y <= 1) {
                return true;
            } else {
                if (this.status === 'moving' && (this.percent > 0 || next)) {
                    let nextX = this.location.x + (this.direction === game.direction.right ? 1 : this.direction === game.direction.left ? -1 : 0);
                    let nextY = this.location.y + (this.direction === game.direction.top ? -1 : this.direction === game.direction.bottom ? 1 : 0);
                    if (nextX - x >= 0 && nextX - x <= 1 && nextY - y >= 0 && nextY - y <= 1) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            }
        }
    }
    get isEnemy() {
        return !isNaN(this.role);
    }
    get data() {
        return {
            status: this.status,
            tick: this.tick,
            percent: this.percent,
            gift: this.gifts.length > 0,
            life: this.life,
            safe: this.safe > 0,
            ship: this.ship,
            speed: this.speed,
            fire: this.fire,
            enemy: this.enemy ? this.enemy.role.player.id : this.enemy,
            location: {
                x: this.location.x,
                y: this.location.y
            },
            direction: this.direction,
            bullets: this.bullets.map(bullet => bullet.data),
            score: this.isEnemy ? { } : this.status !== 'score' ? { } : {
                value: this.score.value,
                current: this.score.current,
                first: this.score.first,
                enemies: this.score.enemies,
                gifts: this.score.gifts
            },
            role: this.isEnemy ? this.role : {
                player: {
                    id: this.role.player.id,
                    name: this.role.player.name
                }
            }
        }
    }
}

class Home {
    constructor() {
        this.current = {
            status: 'life',
            tick: 0
        }
    }
    get status() {
        return this.current.status;
    }
    set status(value) {
        if (this.current.status === value) {
            this.current.tick ++;
        } else {
            this.current.status = value;
            this.current.tick = 0;
        }
    }
    get tick() {
        return this.current.tick;
    }
    get data() {
        return {
            status: this.status,
            tick: this.tick
        }
    }
}

class Battle extends Dispatcher {
    constructor(config, room, board) {
        super();
        this.room = room;
        this.enemies = [];
        this.tanks = room.roles.map(role => new Tank(this, role, game.life));
        this.replay = false;
        this.config = config;
        this.board = board;
        this.board.count = this.tanks.length;
        this.home = new Home();
        this.border = game.borders[this.board.index];
        this.gifts = [];
        this.stopping = 0;
        this.protect = 0;
        this.over = false;
        this.current = {
            status: 'waiting',
            tick: 0
        };

        console.log('游戏即将开始 ', '游戏难度:', this.board.settings.difficulty, typeof this.board.settings.difficulty, '炸弹等级:', this.board.settings.boom, typeof this.board.settings.boom);
    }
    get tick() {
        return this.current.tick;
    }
    pushGift(type) {
        let count = game.count.gifts(this.board.count);
        if (this.gifts.filter(gift => !gift.got).length >= count) {
            this.gifts.splice(this.gifts.findIndex(gift => !gift.got), 1);
        }
        let locations = new Array(this.border.bottom - this.border.top - 1).fill(0).map((v, i) => i + this.border.top + 1).filter(y => y % 2 === 0).reduce((s, y) => s.concat(new Array(this.border.right - this.border.left - 1).fill(0).map((v, i) => i + this.border.left + 1).filter(x => x % 2 === 0).map(x => ({ x, y }))), []);
        locations = locations.filter(location => [...this.tanks, ...this.enemies].filter(tank => tank.life > 0 && tank.tick > game.wait.death).every(tank => !tank.hint(location)))
            .filter(location => !(location.x < 28 && location.x >= 22 && location.y < 28 && location.y >= 22))
            .filter(location => !game.enemies[this.board.index].some(({ x, y }) => Math.abs(location.x - x) < 2 && Math.abs(location.y - y) < 2 ));
        this.gifts.push(new Gift(type, locations[Math.floor(Math.random() * locations.length)]));
    }
    getGift(gift, tank) {
        //this.gifts.splice(this.gifts.indexOf(gift), 1);
        gift.get(tank);
        switch(gift.type) {
            case game.gift.upgrade:
                tank.fire = Math.min(tank.fire + 1, game.bullet.length);
                break;
            case game.gift.boom:
                this.enemies.filter(enemy => enemy.life > 0 && enemy.status === 'moving' || enemy.status === 'stop' || enemy.status === 'original').forEach(enemy => {
                    if (this.board.settings.boom === 0 || this.board.settings.boom >= enemy.life) {
                        enemy.life = 0;
                        enemy.status = 'death';
                    } else {
                        enemy.life -= this.board.settings.boom;
                    }
                    if (enemy.gifts.length) {
                        this.pushGift(enemy.gifts[0]);
                        enemy.gifts = [];
                    }
                });
                break;
            case game.gift.life:
                tank.life = Math.min(tank.life + 1, game.maxLife);
                break;
            case game.gift.stop:
                this.stopping = game.wait.stopFrame;
                break;
            case game.gift.safe:
                tank.safe = game.wait.safeFrame;
                break;
            case game.gift.protect:
                this.board.setWrapper(6, [...this.tanks, ...this.enemies]);
                this.protect = game.wait.protectFrame;
                break;
            case game.gift.ship:
                tank.ship = true;
                break;
            case game.gift.gun:
                tank.fire = Math.min(tank.fire + 3, game.bullet.length);
                break;
        }
    }
    set status(value) {
        if (this.current.status === value) {
            if (this.current.tick % 10 === 0) {
                if (this.enemies.filter(enemy => enemy.status !== 'waiting' && enemy.life > 0).length < game.count.active(this.board.count)) {
                    let index = this.enemies.findIndex(enemy => enemy.status === 'waiting' && enemy.life > 0);
                    while (index !== -1) {
                        let { x, y, d } = game.enemies[this.board.index][index % game.enemies[this.board.index].length];
                        let enemy = this.enemies[index];
                        enemy.location = { x, y };
                        enemy.direction = d;
                        if ([...this.tanks, ...this.enemies].filter(tank => tank.life > 0 && tank.status !== 'waiting').every(tank => !tank.hint(enemy))) {
                            enemy.status = 'born';
                            break;
                        } else {
                            index = this.enemies.findIndex((enemy, i) => i > index && enemy.status === 'waiting' && enemy.life > 0);
                        }
                    }
                }
            }
            this.current.tick ++;
            if (this.stopping) this.stopping--;
            if (this.protect) {
                this.protect--;
                if (!this.protect) {
                    this.board.setWrapper(this.board.settings.wrapper ? 1 : 0, [...this.tanks, ...this.enemies]);
                }
            }
            [...this.tanks, ...this.enemies].forEach((tank, index) => {
                if (tank.safe) tank.safe--;
                if (tank.status === 'born') {
                    if (tank.tick >= game.wait.born) {
                        tank.status = 'stop';
                    } else {
                        tank.status = 'born';
                    }
                } else if (tank.status === 'stop') {
                    if (!tank.isEnemy && this.board.isOver()) {
                        tank.status = 'end';
                    } else {
                        if ((!this.stopping || !tank.isEnemy) && tank.push !== game.direction.none) {
                            tank.status = this.board.hint(this.border, tank.border, tank.direction, tank.ship)
                                && [...this.tanks, ...this.enemies].slice(0, index).filter(t => t.life > 0 && t.status !== 'waiting').every(t => !t.hint(tank, true))
                                && [...this.tanks, ...this.enemies].slice(index + 1).filter(t => t.life > 0 && t.status !== 'waiting').every(t => !t.hint(tank)) ? 'moving' : 'original';
                        } else {
                            tank.status = 'stop';
                        }
                    }
                } else if (tank.status === 'moving') {
                    if (tank.tick >= game.wait.move(tank.speed)) {
                        tank.status = 'stop';
                        if (tank.isEnemy || !this.board.isOver()) {
                            if (tank.move() || !tank.isEnemy && this.board.isIce([tank.location.x - 1, tank.location.x], [tank.location.y - 1, tank.location.y]) && tank.ice !== game.ice && (++tank.ice)) {
                                if (this.stopping && tank.isEnemy) {
                                    tank.status = 'stop';
                                } else {
                                    tank.status = this.board.hint(this.border, tank.border, tank.direction, tank.ship)
                                        && [...this.tanks, ...this.enemies].slice(0, index).filter(t => t.life > 0 && t.status !== 'waiting').every(t => !t.hint(tank, true))
                                        && [...this.tanks, ...this.enemies].slice(index + 1).filter(t => t.life > 0 && t.status !== 'waiting').every(t => !t.hint(tank)) ? 'moving' : 'original';
                                }
                            } else {
                                tank.ice = 0;
                            }
                        } else if (this.board.isOver()) {
                            tank.status = 'end';
                        }
                    } else {
                        tank.status = 'moving';
                        if (!tank.isEnemy) {
                            let gift = this.gifts.find(gift => tank.hint(gift));
                            if (gift) {
                                this.getGift(gift, tank);
                                tank.score.enemies.gifts++;
                            }
                        }
                    }
                } else if (tank.status === 'original') {
                    if (tank.tick >= game.wait.move(tank.speed)) {
                        tank.status = 'stop';
                        if (tank.isEnemy || !this.board.isOver()) {
                            if (tank.move(false)) {
                                if (this.stopping && tank.isEnemy) {
                                    tank.status = 'stop';
                                } else {
                                    tank.status = this.board.hint(this.border, tank.border, tank.direction, tank.ship)
                                    && [...this.tanks, ...this.enemies].slice(0, index).filter(t => t.life > 0 && t.status !== 'waiting').every(t => !t.hint(tank, true))
                                    && [...this.tanks, ...this.enemies].slice(index + 1).filter(t => t.life > 0 && t.status !== 'waiting').every(t => !t.hint(tank)) ? 'moving' : 'original';
                                }
                            }
                        } else if (this.board.isOver()) {
                            tank.status = 'end';
                        }
                    } else {
                        tank.status = 'original';
                    }
                } else if (tank.status === 'death') {
                    if (tank.tick >= game.wait.death && tank.life > 0) {
                        tank.safe = game.wait.bornSafeFrame;
                        tank.status = 'born';
                        let { x, y, d } = game.locations[this.board.index][index % game.locations[this.board.index].length];
                        tank.location = { x, y };
                        tank.direction = d;
                    } else {
                        tank.status = 'death';
                    }
                } else if (tank.status === 'immobilize') {
                    if (tank.tick * game.tick >= game.wait.immobilize * 1000) {
                        tank.status = 'stop';
                        tank.enemy = false;
                    } else {
                        tank.status = 'immobilize';
                    }
                }
                tank.bullets.forEach(bullet => {
                    if (bullet.boom) {
                        bullet.boom++;
                        bullet.tick++;
                    } else {
                        bullet.tick++;
                        let locations = bullet.move();
                        let tiles = locations.map(location => this.board.getTile(this.border, location, bullet.direction));
                        if (locations.some(location => this.board.shot(bullet, this.border, location, bullet.direction, bullet.strong))) {
                            bullet.boom = 1;
                            if (!tank.isEnemy) {
                                bullet.end = locations.map((location, index) => {
                                    let newTile = this.board.getTile(this.border, location, bullet.direction);
                                    let oldTile = tiles[index];
                                    return newTile && oldTile && (newTile.left !== oldTile.left || newTile.right !== oldTile.right);
                                }).some(change => change) ? 'erase' : tiles.some(tile => !tile) ? 'destroy' : 'block';
                            }
                        } else if ([...this.tanks, ...this.enemies].filter(t => t.life > 0 && t.status !== 'waiting' && t.status !== 'born' && t.status !== 'death').some(t => t.isEnemy !== tank.isEnemy && t.bullets.some(b => b.hint(bullet)))) {
                            bullet.boom = game.wait.boom;
                        } else if (this.board.settings.teamDamage && !tank.isEnemy && this.tanks.filter(t => t.life > 0 && t.status !== 'waiting' && t.status !== 'born' && t.status !== 'death').some(t => t.hint(bullet))) {
                            bullet.boom = game.wait.boom;
                        } else if ([...this.tanks, ...this.enemies].filter(t => t.life > 0 && t.status !== 'waiting' && t.status !== 'born' && t.status !== 'death').some(t => t.isEnemy !== tank.isEnemy && t.hint(bullet))) {
                            bullet.boom = game.wait.boom;
                            bullet.end = 'blocked'
                        }
                    }
                });
                tank.bullets = tank.bullets.filter(bullet => bullet.boom <= game.wait.boom);
            });
            this.enemies.forEach(tank => {
                if (!this.stopping) {
                    if (tank.status === 'stop') {
                        tank.end(-1);
                        tank.start(game.ai.turn.stop(this.board.settings.difficulty));
                        if (game.ai.shot(this.board.settings.difficulty)) tank.shot();
                    } else if (tank.status === 'moving') {
                        let direction = tank.push;
                        tank.end(-1);
                        tank.start(game.ai.turn.moving(direction, this.board.settings.difficulty));
                        if (game.ai.shot(this.board.settings.difficulty)) tank.shot();
                    } else if (tank.status === 'original') {
                        let direction = tank.push;
                        tank.end(-1);
                        tank.start(game.ai.turn.original(direction, this.board.settings.difficulty));
                        if (game.ai.shot(this.board.settings.difficulty)) tank.shot();
                    }
                }
            });
            if (this.home.status === 'life') {
                if (this.board.isOver()) {
                    this.home.status = 'death';
                }
            } else if (this.home.status === 'death') {
                this.home.status = 'death';
            }
            this.gifts.forEach(gift => gift.tick--);
            this.gifts = this.gifts.filter(gift => gift.tick > 0);
        } else {
            this.current.status = value;
            this.current.tick = 0;
            if (value === 'fighting') {
                let deathTanks = this.tanks.filter(tank => tank.life === 0);
                if (deathTanks.length) {
                    deathTanks[Math.floor(deathTanks.length * Math.random())].life++;
                }
                this.tanks.forEach((tank, index) => {
                    tank.safe = game.wait.bornSafeFrame;
                    tank.status = 'born';
                    let { x, y, d } = game.locations[this.board.index][index];
                    tank.location = { x, y };
                    tank.direction = d;
                    tank.score = {
                        value: tank.score.value,
                        current: 0,
                        first: false,
                        enemies: [ 0, 0, 0, 0 ],
                        gifts: 0
                    }
                });
                this.enemies = new Array(game.count.all(this.board.count)).fill(0).map((value, index) => index).map(index => this.board.enemies[index % this.board.enemies.length]).map(enemy => new Tank(this, enemy.role, enemy.life, enemy.gifts || 0));
                for (let i = 0; i < this.board.count; i++) {
                    this.enemies.sort((a, b) => Math.random() - 0.5);
                }
                this.gifts = [];
                this.protect = 0;
            } else if (value === 'score' || value === 'ending') {
                this.tanks.forEach(tank => tank.status = 'score');
                let scores = this.tanks.map(tank => tank.score.enemies.map((value, index) => value * game.score.enemies[index]).reduce((s, v) => s + v, 0) + tank.score.gifts * game.score.gifts);
                let max = scores.reduce((s, v) => Math.max(s, v), 0);
                if (scores.filter(score => score === max).length === 1) {
                    let index = scores.findIndex(score => score === max);
                    this.tanks[index].score.first = true;
                    scores[index] += game.score.first;
                }
                this.tanks.forEach((tank, index) => {
                    tank.score.current = scores[index];
                    tank.score.value += scores[index];
                });
            } else if (value === 'replaying') {

            }
        }
    }
    get status() {
        return this.current.status;
    }
    get data() {
        return {
            border: this.border,
            tanks: this.tanks.map(tank => tank.data),
            replay: this.replay,
            enemies: this.enemies.map(tank => tank.data),
            gifts: this.gifts.map(gift => gift.data),
            protect: this.protect,
            home: this.home.data,
            status: this.status,
            tick: this.tick,
            over: this.over
        }
    }
}

//opening: 开幕
//fighting: 战斗中
//settling: 结算中
//over: 结束
//score: 查看结果
//replaying: 回放

class TankGame extends Game {
    constructor(server, room) {
        super(server, room);
        this.battle = new Battle(server.config, room, this.board);
    }
    start() {
        if (super.start()) {
            setTimeout(() => this.tick(), game.tick);
            return true;
        } else {
            return false;
        }
    }
    tick() {
        let tick = Date.now();

        if (this.battle.status === 'waiting') {
            this.board.next();
            this.battle.status = 'opening';
        }
        if (this.battle.status === 'opening') {
            if (this.battle.tick * game.tick >= game.wait.open * 1000) {
                this.battle.status = 'fighting';
            } else {
                this.battle.status = 'opening';
            }
        } else if (this.battle.status === 'fighting') {
            if (this.board.isOver()) {
                if (this.board.killer) {
                    this.battle.replay = this.board.killer.tank.role.player.id
                    this.battle.status = 'replaying';
                } else {
                    this.battle.status = 'settling';
                }
                this.battle.over = true;
            } else if (this.battle.tanks.every(tank => tank.life <= 0)) {
                this.battle.status = 'settling';
                this.battle.over = true;
            } else if (this.battle.enemies.every(enemy => enemy.life <= 0)) {
                this.battle.status = 'settling';
            } else {
                this.battle.status = 'fighting';
            }
        } else if (this.battle.status === 'settling') {
            if (this.battle.tick * game.tick >= game.wait.settle * 1000) {
                if (this.board.isOver()) {
                    if(!this.board.isWin(0)) {
                        // this.over(-1);
                        this.battle.status = 'ending';
                    } else if (this.board.killer) {
                        this.battle.replay = this.board.killer.tank.role.player.id
                        this.battle.status = 'replaying';
                    }
                } else if (this.battle.tanks.every(tank => tank.life <= 0)) {
                    // this.over(-1);
                    this.battle.status = 'ending';
                } else {
                    if (this.board.next()) {
                        this.battle.status = 'score';
                    } else {
                        this.battle.status = 'ending';
                    }
                }
            } else {
                this.battle.status = 'settling';
            }
        } else if (this.battle.status === 'replaying') {
            if (this.battle.tick * game.tick >= game.wait.settle * 1000) {
                this.battle.status = 'ending';
            } else {
                this.battle.status = 'replaying';
            }
        } else if (this.battle.status === 'score') {
            if (this.battle.tanks.every(tank => tank.status === 'waiting')) {
                this.battle.status = 'opening';
            } else {
                if (this.battle.tick * game.tick >= game.wait.score * 1000) {
                    this.battle.tanks.forEach(tank => tank.status = 'waiting');
                }
                this.battle.status = 'score';
            }
        } else if (this.battle.status === 'ending') {
            if (this.battle.tick * game.tick >= game.wait.score * 1000) {
                if (!this.checkWin(0)) {
                    this.over(-1);
                }
            } else {
                this.battle.status = 'ending';
            }
        }

        if (!this.isOver) setTimeout(() => this.tick(), Math.max(0, game.tick - (Date.now() - tick)));
        //else console.log('游戏结束了', this.board.isOver(), this.battle.tanks.every(tank => tank.life <= 0));
    }
    getTank(role) {
        return this.battle.tanks.find(tank => tank.role === role);
    }
    directionStart(role, direction) {
        if (this.battle.over) return;
        this.getTank(role).start(direction);
    }
    directionEnd(role, direction) {
        this.getTank(role).end(direction);
    }
    relive(role, player) {
        this.getTank(role).relive(player);
    }
    shot(role) {
        if (this.battle.over) return;
        this.getTank(role).shot();
    }
    get data() {
        return extend(true, super.data, {
            battle: this.battle.data
        });
    }
}

module.exports = TankGame;
